//Program by:
//Ben Schmidt - bjs778 - 11054018
//Mike Nimeck - mfn028 - 11053045
//Jeff Huang - jlh105 - 11050226

// Gravity update vertex shader
#version 330

// Position and velocity inputs
layout (location = 0) in vec3 gravity_position;
layout (location = 1) in vec3 gravity_velocity;
layout (location = 2) in vec3 gravity_mass;

// Outputs (via transform feedback)
out vec3 position_out;
out vec3 velocity_out;
out vec3 mass_out;

// TBOs containing the position and velocity of other gravity members
uniform samplerBuffer tex_positions;
uniform samplerBuffer tex_velocities;
uniform samplerBuffer tex_mass;

// initial uniform conditions
uniform int num_particles;
uniform float damping_coefficient = 0.99999;

// time varying uniforms
uniform float mass = 1;
uniform float gravitational_constant;
uniform float timestep;
uniform vec3 center_goal = vec3(0.0, 0.0, 0.0);
uniform bool center_toggle;

vec3 gravity_acc(vec3 my_position, vec3 my_mass, vec3 their_position, vec3 their_mass)
{

	vec3 delta = their_position - my_position;
	float r2 = dot(delta, delta);
	
	vec3 force = vec3(0,0,0);
	if (r2 > 0)
	{
		float r = sqrt(r2);
		vec3 dir = delta / r;

                force.xyz = 
			dir * gravitational_constant * 
			( (my_mass.x * their_mass.x ) / r2);
		
		// constant mass test where mass is 1
                //force.xyz = 
		//	dir * gravitational_constant * ( (mass * mass ) / r2);
	}
	
	 vec3 a = ( force / mass );
	 
	
	return a;


}

void main(void)
{
        vec3 acceleration = vec3(0.0);
        vec3 center = vec3(0.0);
        vec3 new_velocity;
        int i;

	vec3 center_goal = vec3(0.0, 0.0, 0.0);
	vec3 d = center_goal - gravity_position;
		
	float center_weight = dot(d, d);
		
	if (center_toggle && (abs(center_weight) > 50000.0f))
	{
	
		acceleration += normalize(center_goal - gravity_position) * 0.1f;
	}
	else
	{
		
		for (i = 0; i < num_particles; i++)
		{
			if (i != gl_VertexID)
			{
				vec3 their_position = texelFetch(tex_positions, i).xyz;
				vec3 their_velocity = texelFetch(tex_velocities, i).xyz;
				vec3 their_mass = texelFetch(tex_mass, i).xyz;

				acceleration += gravity_acc(
						gravity_position,
						gravity_mass,
						their_position,
						their_mass) * 5.0;
				
				center += their_position;
			}
		}
		
		//acceleration += normalize(center_goal - gravity_position) * 0.001f;
	}
	
        // Update position based on prior velocity and timestep
        position_out = gravity_position + gravity_velocity * timestep;

        // Update velocity based on calculated acceleration
	if (length(acceleration) > 0.01)
		acceleration = normalize(acceleration) * 0.01;
	
        new_velocity = 
		gravity_velocity * damping_coefficient + acceleration * timestep;

        // clamp speed
        if (length(new_velocity) > 1.5)
                new_velocity = normalize(new_velocity) * 1.5;
	
        velocity_out = new_velocity;
	mass_out = gravity_mass;

        gl_Position = vec4(gravity_position * 0.1, 1.0);
}
